//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// (C) Copyright 2006 Marvell International Ltd.
// All Rights Reserved
//
//
//------------------------------------------------------------------------------
//
//  File: backlight.c
//
//  Backlight PDD driver source code, Littleton-specific
//
#include <windows.h>
#include <ceddk.h>
#include <nkintr.h>
#include "monahans_base_regs.h"
#include "xllp_mfp.h"
#include "xllp_mfp_plat.h"
#include "arava.h"

extern "C"
{
#include "xllp_gpio_proc.h"
}
#include "xllp_gpio_plat.h"

extern "C"
{
#include "xllp_bkl_micco_B0.h"
}

#include <ipm_api.h>

#ifdef  RETAIL_DEBUG
#ifndef DEBUG
#define DEBUG 1
extern DBGPARAM dpCurSettings;
#undef DEBUGMSG
#define DEBUGMSG RETAILMSG
#endif
#endif

#ifdef DEBUG
#define ZONE_BACKLIGHT      DEBUGZONE(0)
#define ZONE_FUNCTION       DEBUGZONE(1)
#define ZONE_ERROR          DEBUGZONE(15)
#else
#define ZONE_BACKLIGHT      1
#define ZONE_FUNCTION       1
#define ZONE_ERROR          1
#endif

XLLP_GPIO_T* gpio_reg = 0;
XLLP_VUINT32_T* mfp_reg = 0;
#define MFP_SIZE 0x700
CLIENT_ID ipm_client_id = 0;

static BOOL is_state_on(CEDEVICE_POWER_STATE state)
{
    return state == D0;
}

static void IPM_notify(BOOL is_on);

extern "C"
void backlight_set(BOOL is_on)
{
    if(is_on)
    {
        XllpBklSetPwm(95);
        XllpBklSetCurrent(32);  // 32mA
    }
    else
    {
        XllpBklSetPwm(1);
		XllpBklSetCurrent(1);
    }
}

//-----------------------------------------------------------------------------
//  Initialize hardware etc
//  Returned DWORD will be passed to BacklightDeInit and should be used to store context if necessary
//  pDeviceState should be set to the start state of the backlight (usually D0)
//
extern "C"
DWORD BacklightInit(LPCTSTR pContext, LPCVOID lpvBusContext, CEDEVICE_POWER_STATE *pDeviceState)
{
	//IPM
    IPM_STATUS_T status;

    PHYSICAL_ADDRESS PA;
	if (!mfp_reg)
	{
		PA.QuadPart = MONAHANS_BASE_REG_PA_MFP;
		mfp_reg = (XLLP_VUINT32_T*)MmMapIoSpace(PA, MFP_SIZE, FALSE);
	}
	
    if (!gpio_reg)
    {
        PA.QuadPart = MONAHANS_BASE_REG_PA_GPIO;
        gpio_reg = (XLLP_GPIO_T*) MmMapIoSpace(PA, sizeof(XLLP_GPIO_T), FALSE);
    }

    NKDbgPrintfW(L"In BacklightInit mfp_reg 0x%08x, gpio_reg 0x%08x\r\n", mfp_reg, gpio_reg);

    // IPM Registration:
    NKDbgPrintfW (_T("[BKL1] Sending Registration Request for driver \r\n"));
    status = IPM_Register(_T("BKL1:"), &ipm_client_id, 3000);

    if (status == IPM_STATUS_IPM_DISABLED)
		NKDbgPrintfW (_T("[BKL1] NOIPM. \r\n"));
    else if (status != IPM_STATUS_SUCCESS)
        NKDbgPrintfW (_T("[BKL1] Registration Failed, IPM Error %d\r\n"));

    *pDeviceState = D0;

    if (!XllpBklMiccoInit())
        return FALSE;

    BOOL is_on = is_state_on(*pDeviceState);
    backlight_set(is_on);
    IPM_notify(is_on);

    return TRUE;

}

extern "C"
void BacklightDeInit(DWORD dwContext)
{
    DEBUGMSG(ZONE_BACKLIGHT, (TEXT("BKL: De-Init\r\n")));
    if (gpio_reg != NULL) {
       MmUnmapIoSpace((PVOID)gpio_reg, sizeof(XLLP_GPIO_T));
    }
    if (mfp_reg != NULL) {
       MmUnmapIoSpace((PVOID)mfp_reg, MFP_SIZE);
    }

    IPM_DeRegister(ipm_client_id,3000);

    return;
}

static void IPM_notify(BOOL is_on)
{
    DWORD dwProcState;
    BOOL ret;

    if(is_on)
	dwProcState = IPM_PROCESSOR_RING_OSC_RDY |IPM_PROCESSOR_D0_RDY;
    else
        dwProcState = IPM_PROCESSOR_RING_OSC_RDY |IPM_PROCESSOR_D0_RDY 
                      | IPM_PROCESSOR_D2_RDY | IPM_PROCESSOR_D1_RDY;

    NKDbgPrintfW(_T("[BKL1] Notify IPM Ready For Processor state for driver %d\r\n"),ipm_client_id);
    if (IPM_NotifyReadyForProcState(ipm_client_id, dwProcState, 3000) == IPM_STATUS_SUCCESS)
    {
	// NKDbgPrintfW(_T("[BKL1] Notify IPM Ready For Processor state for driver Completed\r\n"));
    }
    else
	NKDbgPrintfW(_T("[BKL1] Notify IPM Ready For Processor state for driver FAILED\r\n"));


    if(is_on)
        ret = IPM_SetMinOp(ipm_client_id, IPM_OP_104MHZ ,3000);
    else
        ret = IPM_ReleaseMinOp(ipm_client_id, 1000);

    if (ret == IPM_STATUS_SUCCESS)
    {
        //NKDbgPrintfW(_T("[%s] MinOP Set/Release Success!\r\n"),pController->szName);
    } else
        NKDbgPrintfW(_T("[BKL1:] MinOP Set/Release FAILED\r\n"));
}

extern "C"
BOOL BackLightSetState(DWORD dwContext, CEDEVICE_POWER_STATE state)
{
    // sets the backlight state (turns the backlight on and off)
    DEBUGMSG(ZONE_FUNCTION, (L"+BackLightSetState(0x%08x)\r\n", (DWORD) state));

    BOOL is_on = is_state_on(state);

    backlight_set(is_on);
    IPM_notify(is_on); 

    return TRUE;
}

extern "C"
UCHAR BacklightGetSupportedStates()
{
    //support D0, D4:
    return DX_MASK(D0) | DX_MASK(D4);
}

extern "C"
DWORD BacklightIOControl(DWORD dwOpenContext, DWORD dwIoControlCode, LPBYTE lpInBuf, 
                   DWORD nInBufSize, LPBYTE lpOutBuf, DWORD nOutBufSize, 
                   LPDWORD lpBytesReturned)
{
    // For IOCTls that MDD doesn't know. ie non-pm IOCTLs
    return ERROR_NOT_SUPPORTED;
}

extern "C"
void BacklightRegChanged()
{
    // Called when the MDD gets a backlight registry changed event
    // eg: read brightness settings from registry and update backlight accordingly
    return;
}

extern "C"
void BacklightPwrSrcChanged(BOOL fOnAC)
{
    // Called when the MDD gets a power source changed (AC->DC or vice-versa) event
    // fOnAC will indicate whether the power source is now AC. TRUE->AC FALSE->Battery
    // eg: update brightness of backlight according to user settings
    return;
}
